package com.wcq.studentbackend.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wcq.studentbackend.common.R;
import com.wcq.studentbackend.dto.ClassDTO;
import com.wcq.studentbackend.dto.ClassRequestDTO;
import com.wcq.studentbackend.dto.ExamDTO;
import com.wcq.studentbackend.dto.GradeDTO;
import com.wcq.studentbackend.entity.Student;
import com.wcq.studentbackend.service.ClassService;
import com.wcq.studentbackend.service.ExamService;
import com.wcq.studentbackend.service.GradeService;
import com.wcq.studentbackend.service.StudentService;
import com.wcq.studentbackend.util.PasswordUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/api/students")
@Api(value = "学生信息管理")
public class StudentController {
    @Autowired
    private StudentService studentService;

    @Autowired
    private ExamService examService;

    @Autowired
    private ClassService classService;

    @Autowired
    private GradeService gradeService;

    @Autowired
    public StudentController(StudentService studentService, ClassService classService) {
        this.studentService = studentService;
        this.classService = classService;
    }

    // 分页查询接口（支持多条件筛选）
    @GetMapping("/page")
    @ApiOperation(value = "分页查询学生信息接口")
    public R<Page<Student>> pageQuery(
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "10") Integer pageSize,
            @RequestParam(required = false) String name,
            @RequestParam(required = false) String stuNo,
            @RequestParam(required = false) Integer classId
    ) {
        log.info("分页查询学生信息，page={}, pageSize={}, name={}, stuNo={}, classId={}", 
                page, pageSize, name, stuNo, classId);

        // 构造分页构造器
        Page<Student> pageInfo = new Page<>(page, pageSize);

        // 构造条件构造器
        LambdaQueryWrapper<Student> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.like(StringUtils.hasText(name), Student::getName, name);
        queryWrapper.like(StringUtils.hasText(stuNo), Student::getStuNo, stuNo);
        queryWrapper.eq(classId != null, Student::getClassId, classId);
        // 添加排序条件
        queryWrapper.orderByDesc(Student::getUpdateTime);

        // 执行查询
        studentService.page(pageInfo, queryWrapper);

        return R.success(pageInfo);
    }

    // 新增学生
    @PostMapping
    @ApiOperation(value = "新增学生接口")
    public R<Student> add(@RequestBody Student student) {
        log.info("新增学生 - 接收到的数据：{}", student);
        
        // 设置默认值或在Service层处理
        if (student.getRole() == null) {
            student.setRole("student");
        }
        
        // 加密密码
        if (student.getPassword() == null || student.getPassword().isEmpty()) {
            // 使用工具类加密默认密码
            student.setPassword(PasswordUtil.getDefaultEncodedPassword());
            log.info("为新学生 {} 设置了加密后的默认密码", student.getStuNo());
        } else {
            // 加密用户提供的密码
            student.setPassword(PasswordUtil.encode(student.getPassword()));
            log.info("为新学生 {} 加密了提供的密码", student.getStuNo());
        }

        if (student.getCreateTime() == null) {
            student.setCreateTime(java.time.LocalDateTime.now());
        }
        student.setUpdateTime(java.time.LocalDateTime.now());

        log.info("新增学生 - 处理后准备保存的数据：{}", student);

        boolean success = studentService.save(student);
        if (success) {
            log.info("新增学生成功，ID: {}", student.getId());

            ClassDTO classById = classService.getClassById(student.getClassId());
            ClassRequestDTO classRequestDTO = new ClassRequestDTO();
            BeanUtils.copyProperties(classById, classRequestDTO);
            classRequestDTO.setStudentCount(classById.getStudentCount() + 1);
            classService.updateClass(student.getClassId(), classRequestDTO);
            log.info("更新班级信息成功，班级ID: {}", student.getClassId());
            
            return R.success(student);
        }
        log.error("新增学生操作失败，数据库保存返回false。Student data: {}", student);
        return R.error("新增学生失败，请稍后再试或联系管理员。");
    }

    // 更新学生信息
    @PutMapping("/{id}")
    @ApiOperation(value = "更新学生信息接口")
    public R<Student> update(@PathVariable Integer id, @RequestBody Student student) {
        log.info("更新学生信息：id={}, student={}", id, student);
        student.setId(id);
        boolean success = studentService.updateById(student);
        if (success) {

            return R.success(student);
        }
        return R.error("更新学生信息失败");
    }

    // 删除学生
    @DeleteMapping("/{id}")
    @ApiOperation(value = "删除学生接口")
    public R<String> delete(@PathVariable Integer id) {
        log.info("删除学生：id={}", id);
        try {
            // 获取学生信息
            Student student = studentService.getById(id);
            if (student == null) {
                return R.error("学生不存在");
            }
            // 获取班级信息
            Integer classId = student.getClassId();
            if (classId != null) {
                ClassDTO classById = classService.getClassById(classId);
                if (classById != null) {
                    // 创建新的班级请求DTO并复制属性
                    ClassRequestDTO classRequestDTO = new ClassRequestDTO();
                    BeanUtils.copyProperties(classById, classRequestDTO);
                    // 减少班级人数
                    classRequestDTO.setStudentCount(classById.getStudentCount() - 1);
                    classService.updateClass(classId, classRequestDTO);
                }
            }
            // 删除学生
            boolean success = studentService.removeById(id);
            if (success) {
                return R.success("删除成功");
            }
            // 如果删除失败，恢复班级人数
            if (classId != null) {
                ClassDTO classById = classService.getClassById(classId);
                if (classById != null) {
                    ClassRequestDTO classRequestDTO = new ClassRequestDTO();
                    BeanUtils.copyProperties(classById, classRequestDTO);
                    classRequestDTO.setStudentCount(classById.getStudentCount() + 1);
                    classService.updateClass(classId, classRequestDTO);
                }
            }
            log.error("删除学生操作失败，数据库删除返回false。Student ID: {}", id);
            return R.error("删除失败");
        } catch (Exception e) {
            log.error("删除学生时发生异常", e);
            return R.error("删除失败：" + e.getMessage());
        }
    }

    // 根据ID获取学生信息 (为编辑功能添加)
    @GetMapping("/{id}")
    @ApiOperation(value = "根据ID获取学生信息接口")
    public R<Student> getStudentById(@PathVariable Integer id) {
        log.info("查询学生信息 (for edit)，id={}", id);
        Student student = studentService.getById(id); // 假设 studentService 有 getById 方法
        if (student != null) {
            return R.success(student);
        }
        return R.error("未找到ID为 " + id + " 的学生");
    }

    // 根据学号获取学生信息
    @GetMapping("/info")
    @ApiOperation(value = "根据学号获取学生信息接口")
    public R<Student> getInfo(@RequestParam String stuNo) {
        log.info("根据学号查询学生信息：stuNo={}", stuNo);
        Student student = studentService.getByStuNo(stuNo);
        if (student == null) {
            return R.error("该学生不存在");
        }
        return R.success(student);
    }

    @GetMapping("/all-exams")
    @ApiOperation(value = "获取当前学生的考试信息接口")
    public R<List<ExamDTO>> getStudentExams(Authentication authentication) {
        if (authentication == null || !authentication.isAuthenticated()) {
            log.warn("Attempt to access /all-exams without authentication.");
            return R.error("用户未认证");
        }
        // The name from authentication is typically the username used for login (stuNo in this case)
        String stuNo = authentication.getName(); 
        
        log.info("Fetching exams for student stuNo: {}", stuNo);
        List<ExamDTO> exams = examService.getExamsByStudentStuNo(stuNo);

        if (exams == null) { // Defensive check, though service should return empty list
            log.warn("Exam service returned null for stuNo: {}, returning empty list.", stuNo);
            return R.success(Collections.emptyList());
        }

        if (exams.isEmpty()){
            log.info("No exams found for student stuNo: {}. Returning empty list.", stuNo);
        }
        // Always return success, even if the list is empty.
        // The frontend can display a "no exams" message if the data array is empty.
        log.info("Found {} exams for student stuNo: {}", exams.size(), stuNo);
        return R.success(exams);
    }

    @GetMapping("/my-class-info")
    @ApiOperation(value = "获取当前学生的班级信息接口")
    public R<ClassDTO> getMyClassInfo(Authentication authentication) {
        if (authentication == null || !authentication.isAuthenticated()) {
            log.warn("Attempt to access /my-class-info without authentication.");
            return R.error("用户未认证");
        }
        String stuNo = authentication.getName();
        log.info("Fetching class info for student stuNo: {}", stuNo);

        Student student = studentService.getByStuNo(stuNo);
        if (student == null) {
            log.warn("Student not found with stuNo: {} when fetching class info.", stuNo);
            return R.error("无法获取学生信息，无法查询班级。_INVALID_STUDENT"); // Added suffix for easier frontend distinction if needed
        }

        if (student.getClassId() == null) {
            log.info("Student {} (stuNo: {}) has no classId assigned.", student.getName(), stuNo);
            // Return success with null data. Frontend can check for null data.
            // The R.success(T object) method will set code=1 and data=object (which is null here).
            // The msg field in R will remain null by default for R.success().
            return R.success(null);
        }

        ClassDTO classDTO = classService.getClassById(student.getClassId());
        if (classDTO == null) {
            log.warn("Class not found with id: {} for student stuNo: {}", student.getClassId(), stuNo);
            return R.error("未能找到班级信息 (ID: " + student.getClassId() + ")。_CLASS_NOT_FOUND");
        }

        log.info("Successfully fetched class info for student {}: {}", stuNo, classDTO.getClassName());
        return R.success(classDTO);
    }

    @GetMapping("/my-grades")
    @ApiOperation(value = "获取当前学生的成绩信息接口")
    public R<List<GradeDTO>> getMyGrades(Authentication authentication) {
        if (authentication == null || !authentication.isAuthenticated()) {
            log.warn("Attempt to access /my-grades without authentication.");
            return R.error("用户未认证");
        }
        String stuNo = authentication.getName();
        log.info("Fetching grades for student stuNo: {}", stuNo);

        List<GradeDTO> grades = gradeService.getGradesByStudentStuNo(stuNo);

        if (grades == null) {
            log.warn("Grade service returned null for stuNo: {}, returning empty list.", stuNo);
            return R.success(Collections.emptyList());
        }

        if (grades.isEmpty()){
            log.info("No grades found for student stuNo: {}. Returning empty list.", stuNo);
        }
        log.info("Found {} grades for student stuNo: {}", grades.size(), stuNo);
        return R.success(grades);
    }

    @GetMapping("/dashboard-stats")
    @ApiOperation(value = "获取学生仪表盘统计数据接口")
    public R<Map<String, Object>> getDashboardStats(Authentication authentication) {
        if (authentication == null || !authentication.isAuthenticated()) {
            log.warn("Attempt to access /dashboard-stats without authentication.");
            return R.error("用户未认证");
        }
        String stuNo = authentication.getName();
        log.info("Fetching dashboard stats for student stuNo: {}", stuNo);

        try {
            Student student = studentService.getByStuNo(stuNo);
            if (student == null) {
                log.warn("Student not found with stuNo: {}", stuNo);
                return R.error("学生信息不存在");
            }

            // 获取学生成绩统计
            List<GradeDTO> grades = gradeService.getGradesByStudentStuNo(stuNo);
            
            // 计算统计数据
            int totalExams = grades.size();
            double averageScore = grades.stream()
                .mapToInt(GradeDTO::getScore)
                .average()
                .orElse(0.0);
            
            // 获取学生成绩趋势
            List<Map<String, Object>> gradeTrend = grades.stream()
                .map(grade -> {
                    Map<String, Object> trend = new HashMap<>();
                    trend.put("examName", grade.getExamName());
                    trend.put("score", grade.getScore());
                    return trend;
                })
                .collect(Collectors.toList());

            // 获取科目成绩分布
            List<Map<String, Object>> subjectGrades = grades.stream()
                .collect(Collectors.groupingBy(
                    GradeDTO::getExamSubject,
                    Collectors.collectingAndThen(
                        Collectors.toList(),
                        list -> {
                            double avg = list.stream()
                                .mapToInt(GradeDTO::getScore)
                                .average()
                                .orElse(0.0);
                            Map<String, Object> subject = new HashMap<>();
                            subject.put("subject", list.get(0).getExamSubject());
                            subject.put("averageScore", avg);
                            return subject;
                        }
                    )
                ))
                .values()
                .stream()
                .collect(Collectors.toList());

            // 计算班级排名
            int classRank = 1;
            if (student.getClassId() != null) {
                List<Student> classmates = studentService.getByClassId(student.getClassId());
                if (classmates != null && !classmates.isEmpty()) {
                    // 获取所有同学的成绩
                    List<Double> classAverages = classmates.stream()
                        .map(classmate -> {
                            List<GradeDTO> classmateGrades = gradeService.getGradesByStudentStuNo(classmate.getStuNo());
                            return classmateGrades.stream()
                                .mapToInt(GradeDTO::getScore)
                                .average()
                                .orElse(0.0);
                        })
                        .sorted(Comparator.reverseOrder())
                        .collect(Collectors.toList());

                    // 计算当前学生的排名
                    for (Double avg : classAverages) {
                        if (avg > averageScore) {
                            classRank++;
                        }
                    }
                }
            }

            Map<String, Object> stats = new HashMap<>();
            stats.put("totalExams", totalExams);
            stats.put("averageScore", averageScore);
            stats.put("classRank", classRank);
            stats.put("gradeTrend", gradeTrend);
            stats.put("subjectGrades", subjectGrades);

            return R.success(stats);
        } catch (Exception e) {
            log.error("Error fetching dashboard stats for student: " + stuNo, e);
            return R.error("获取仪表盘统计数据失败：" + e.getMessage());
        }
    }

    @PostMapping("/change-password")
    @ApiOperation("学生修改密码")
    public R<?> changePassword(@RequestBody Map<String, String> body, @RequestHeader("Authorization") String authHeader) {
        log.info("开始处理修改密码请求");
        
        String oldPassword = body.get("oldPassword");
        String newPassword = body.get("newPassword");
        if (oldPassword == null || newPassword == null) {
            log.warn("修改密码请求参数为空");
            return R.error("参数不能为空");
        }
        
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            log.warn("修改密码请求未提供有效的Authorization头");
            return R.error("未授权");
        }
        
        String token = authHeader.substring(7);
        log.info("从请求中提取的token: {}", token.substring(0, 20) + "...");
        
        String subject;
        try {
            subject = com.wcq.studentbackend.util.JwtUtil.getUsernameFromTokenStatic(token);
            log.info("成功解析token，subject: {}", subject);
        } catch (Exception e) {
            log.error("Token解析失败", e);
            return R.error("Token无效");
        }
        
        // subject 形如 student:20230001
        String[] parts = subject.split(":", 2);
        if (parts.length != 2 || !"student".equalsIgnoreCase(parts[0])) {
            log.warn("无效的token subject格式: {}", subject);
            return R.error("Token无效或非学生用户");
        }
        
        String stuNo = parts[1];
        log.info("从token中提取的学号: {}", stuNo);
        
        Student student = studentService.getByStuNo(stuNo);
        if (student == null) {
            log.warn("未找到对应的学生信息: {}", stuNo);
            return R.error("用户不存在");
        }
        
        if (!PasswordUtil.matches(oldPassword, student.getPassword())) {
            log.warn("旧密码验证失败: {}", stuNo);
            return R.error("旧密码错误");
        }
        
        student.setPassword(PasswordUtil.encode(newPassword));
        boolean success = studentService.updateById(student);
        if (success) {
            log.info("密码修改成功: {}", stuNo);
            return R.success("密码修改成功");
        } else {
            log.error("密码修改失败: {}", stuNo);
            return R.error("密码修改失败");
        }
    }
}